/**============================================================================
 Confidential Information - Limited distribution to authorized persons only.
 This software is protected as an unpublished work under the U.S. Copyright
 Act of 1976.

 Copyright (c) 2012, BluePhoenix Solutions, Inc. All rights reserved.
 ----------------------------------------------------------------------------
 file......: Utils.java
 Author....: Vyacheslav Kovalyov
 Created...: 2/15/12

 Description:

 ============================================================================*/
package ru.monyag.android.vibralarm.utils;

import ru.monyag.android.vibralarm.alarm.DayOfWeek;

import java.io.Closeable;
import java.util.*;

import static org.apache.commons.lang.StringUtils.EMPTY;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static ru.monyag.android.vibralarm.alarm.DayOfWeek.*;
import static ru.monyag.android.vibralarm.utils.Constants.COMMA_SEPARATOR;

/**
 * @author Vyacheslav Kovalyov
 * @version 1.0
 */
public abstract class Utils {

    public static Collection<DayOfWeek> parseDaysString(String days) {
        Set<String> splittedDays = splitByComma(days);
        List<DayOfWeek> daysSet = new ArrayList<DayOfWeek>();

        for (String s : splittedDays) {
            try {
                daysSet.add(DayOfWeek.valueOf(s.toUpperCase()));
            } catch (Exception ignored) {
            }
        }

        return cleanDayOfWeeks(daysSet);
    }

    private static Set<String> splitByComma(String str) {
        Set<String> set = new HashSet<String>();
        String[] splittedArray = str.split(COMMA_SEPARATOR);

        for (String s : splittedArray) {
            String cleanStr = s.trim();
            if (isNotBlank(cleanStr)) {
                set.add(cleanStr);
            }
        }

        return set;
    }


    //todo


    public static String makeDaysString(List<DayOfWeek> days) {
        if (days == null || days.isEmpty()) {
            return EMPTY;
        }

        List<DayOfWeek> cleanDays = cleanDayOfWeeks(days);
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < cleanDays.size(); i++) {
            sb.append(cleanDays.get(i));
            if (i < cleanDays.size() - 1) {
                sb.append(COMMA_SEPARATOR);
            }
        }

        return sb.toString();
    }

    private static List<DayOfWeek> cleanDayOfWeeks(List<DayOfWeek> days) {

        if (days.size() <= 1) {
            return days;
        }

        //check of EveryDay
        if (isEveryDay(days)) {
            return Arrays.asList(EVERY_DAY);
        }

        //check weekends
        if (isWeekends(days)) {
            return Arrays.asList(WEEKENDS);
        }

        //check weekdays
        if (isWeekDays(days)) {
            return Arrays.asList(WEEKDAYS);
        }

        //cleanup
        Set<DayOfWeek> daysSet = new HashSet<DayOfWeek>(days);
        if (daysSet.containsAll(ALL_WEEKEND_DAYS) || daysSet.contains(WEEKENDS)) {
            daysSet.removeAll(ALL_WEEKEND_DAYS);
            daysSet.add(WEEKENDS);
        } else {
            if (containsOneOrMore(ALL_WEEKEND_DAYS, daysSet) && daysSet.contains(WEEKENDS)) {
                daysSet.remove(WEEKENDS);
            }
        }

        if (daysSet.containsAll(ALL_WEEK_DAYS) || daysSet.contains(WEEKDAYS)) {
            daysSet.removeAll(ALL_WEEK_DAYS);
            daysSet.add(WEEKDAYS);
        } else {
            if (containsOneOrMore(ALL_WEEK_DAYS, daysSet) && daysSet.contains(WEEKDAYS)) {
                daysSet.remove(WEEKDAYS);
            }
        }

        return new ArrayList<DayOfWeek>(daysSet);
    }

    private static boolean isWeekDays(List<DayOfWeek> days) {
        if (isEveryDay(days)) return false;
        if ((days.contains(WEEKDAYS) || days.containsAll(ALL_WEEK_DAYS)) &&
                !(days.contains(WEEKENDS) || containsOneOrMore(ALL_WEEKEND_DAYS, days))) {
            return true;
        }

        return false;
    }

    private static boolean isWeekends(List<DayOfWeek> days) {
        if (isEveryDay(days)) return false;
        if ((days.contains(WEEKENDS) || days.containsAll(ALL_WEEKEND_DAYS)) &&
                !(days.contains(WEEKDAYS) || containsOneOrMore(ALL_WEEK_DAYS, days))) {
            return true;
        }

        return false;
    }

    private static boolean isEveryDay(List<DayOfWeek> days) {
        if (days.contains(EVERY_DAY)) {
            return true;
        }

        if (((days.containsAll(ALL_WEEK_DAYS) || days.contains(WEEKDAYS)) &&
                (days.containsAll(ALL_WEEKEND_DAYS) || days.contains(WEEKENDS))) ||
                days.containsAll(ALL_DAYS)) {
            return true;
        }

        return false;
    }

    public static boolean containsOneOrMore(Collection<?> baseCollection, Collection<?> collection) {
        for (Object o : collection) {
            if (baseCollection.contains(o)) {
                return true;
            }
        }

        return false;
    }


    public static void closeSafely(Closeable closable) {
        try {
            if (closable != null) {
                closable.close();
            }
        } catch (Exception e) {
            //do nothing
        }
    }

    private static final List<DayOfWeek> ALL_WEEKEND_DAYS = Arrays.asList(
            SUNDAY,
            SATURDAY
    );

    private static final List<DayOfWeek> ALL_WEEK_DAYS = Arrays.asList(
            MONDAY,
            TUESDAY,
            WEDNESDAY,
            THURSDAY,
            FRIDAY
    );

    private static final List<DayOfWeek> ALL_DAYS = Arrays.asList(SUNDAY,
            MONDAY,
            TUESDAY,
            WEDNESDAY,
            THURSDAY,
            FRIDAY,
            SATURDAY);
}
